home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-02
/
pas2c.zip
/
PAS2C.DOC
< prev
next >
Wrap
Text File
|
1993-01-04
|
9KB
|
210 lines
PAS2C.DOC
Linking Turbo Pascal and Turbo C
December 23, 1987 Martin Weigel
Synopsis:
Recently, I had need to link Turbo C and Turbo Pascal code together. This
summarizes my efforts, and provides a useful utility routine. This document
is *not* tutorial but is solely intended for technically astute users. I do
entertain suggestions on the problem, and its solution(s), but *not* on the
material or its presentation. *Only* source code is presented here, and
you will have to have the required programs to make use of the material.
I encourage *free* distribution of this material. I strictly prohibit
selling PASOBJ (give it away, *but* don't sell it).
Please let Borland know how you feel about their OBJ capability (or lack
thereof).
Requires:
Borland Turbo C
Borland Turbo Pascal 4.0
Microsoft LIB
---------------------------------------
PASOBJ:
Both Turbo C and Turbo Pascal 4 are fantastic compilers. Turbo C offers
reasonable compilation speed, and *very* good code production. Turbo Pascal
offers excellent type checking, screamingly fast compilation, and units.
In some projects, it would be nice to capitalize on the strengths of both
of these Borland products. Unfortunately, there are some very basic
compatibility problems which must be overcome before this dream can be
successfully realized.
With the help of Kim Kokonnen, I have developed an interim solution, which
should be effective for most applications. At least until Borland does
something about the problems.
The first problem is one of segment naming. In order to import OBJ files,
the OBJ files have to be structure with some *very* specific rules:
- The code must be in a segment called CODE or CSEG
- The data must be in a segment called DATA or DSEG
- There must be no initialized data in the OBJ file
- All symbols *must* have legal Pascal identifiers
- There must be *no* groups or classes
Turbo C breaks *all* of these rules when it is producing code. First,
the code segment name is _TEXT or xxx_TEXT, and the data is in two
segments: _BSS for unitialized data and _DATA for initialized data.
It "groups" _BSS and _DATA into a single segment. Initialized data is
produced for every string constant and initialized variable (put into
the _DATA segment). Turbo C assigns class names to all segments. Last,
Turbo C *itself* generates identifiers which are not legal in Pascal
(identifiers with an '@' symbol in the name).
All of these problems but the last one can be solved by instructing the
Turbo C compiler to use different segment, group and class naming
conventions, and by being rigid about the style of C code being used.
The problem with the '@' sign in identifiers *cannot* be solved this
way, because the C programmer is not in control over the use of these
functions.
The Turbo C compiler will produce an '@' identifier every time it must
use an "intrinsic" function. An intrinsic function can be viewed as
an extension to the instruction set of the machine. Some of these
intrinsic functions include Long Divide, Long Shift, and Structure
Passing.
Another problem with changing the segment naming during the C compilation
is that this technique only works if you have access to the C source code.
I don't have a copy of the C Library Run-time source, and some of the
routines I am interested in linking to are in that library.
The PASOBJ solves most of the problems. To compile PASOBJ, you will need
the Turbo C compiler (if you don't have it, this is all pretty much
useless to you anyway). Compile PASOBJ.C to PASOBJ.EXE using small model,
no floating point (this is not critical, but results in the smallest EXE
file).
PASOBJ takes one or two parameters. Both parameters are OBJ file names.
If only one parameter is given, PASOBJ will process the OBJ file to
itself (using a temporary file). If two names are given, the first file
is taken as an input file, the second as the output file. WARNING: If
the file fed to PASOBJ is *not* an OBJ file, strange things will happen!
The .OBJ extension *must* be specified.
PASOBJ massages the OBJ file, changing segment names as appropriate for
use with Turbo Pascal 4.0, and changing '@' characters in identifiers
to benign '_' characters.
Example:
lib cc *strlen -- extract strlen.obj from cc.lib
pasobj strlen.obj -- massage it for $L inclusion
CINTRIN.PAS is the Pascal source code for a unit that will satisfy all
of the C Intrinsic references. Edit, and the run batch file MAKECIN
to produce the CINTRIN.TPU unit.
---------------------------------------
SAVEREG:
The Turbo C compiler produces its best code when it is allowed to use
SI and DI as general registers. When Pascal is used to call a C function,
this works, because C functions that use SI and DI save and restore the
register values appropriately. If the C function calls a Pascal routine,
the Pascal routine is at liberty to destroy the values contained in SI
and DI. Turbo C provides an option (-r-) to support this, at the cost
of worsening code generation. The two macros in SAVEREG.H also solve the
problem, in a more efficient way. Every call from C to Pascal is to
be wrapped in a save_registers/restore_registers pair:
save_registers;
PASCAL_PROCEDURE();
restore_registers;
save_registers saves the contents of SI and DI before the call,
restore_registers restores the contents of SI and DI after the call.
The PASCAL program must make a POINTER called __rsp available globally,
and must point it to an area to be used as a save stack. 2 words are
used on this stack every time save_registers is used. (see SAVEREG.PAS
for an example that can be compiled into a unit).
var
__rsp : Pointer;
SiDiStack : array [0..10] of Word;
...
begin
__rsp := @SiDiStack[0];
...
end.
save_registers and restore_registers are implemented as macros for
efficiency.
---------------------------------------
STD.H:
This is just my standards file, for machine portability. When compiling
C programs for use by Pascal, I prefer COMPACT model. So STD.H enforces
COMPACT model if the PASCAL define is given.
---------------------------------------
An Example: TASK in C and Pascal
Files TASK.C, TASK.H and TASK.PAS implement a non-preemptive multi-tasker
for Turbo Pascal V4.0, in C. See the source files for more documentation.
Compile TASK.C in COMPACT model. Unit TASK.PAS requires CINTRIN.TPU and
SETJMP.OBJ (from CC.LIB):
lib \lib\cc *setjmp -- pull C setjmp/longjmp functions from lib
pasobj setjmp.obj -- massage them into TPAS 4 format
tpc task -- compile task unit
This tasker can run tasks written in either C or Pascal. It is not at
all fancy, but serves 99.9% of all my needs. If you feel inclined,
expand on it, but please send the results (including source) back to
CompuServe.
---------------------------------------
Outstanding Problems:
Every time a constant string is used in Turbo C, it places the string into
initialized data (_DATA). Unfortunately, Turbo Pascal 4.0 cannot (will not?)
import an OBJ file with initialized data (per the manual). This means that
C library routines such as atoi cannot be used (becauses it, in turn uses
__ctypes, which is an initialized array). Also, any user code like:
send_string("showpage\n");
will not work.
A work-around for the string problem is to define the strings in the
Turbo Pascal section, as in:
const
_string1 : String[10] = 'showpage'#10#0;
and rework the C code to be:
IMPORT TEXT *string1; /* see STD.H for IMPORT and TEXT */
send_string(string1 + 1);
This is *not* nice, in fact, it's downright ugly. Any suggestions?
Another problem (much worse, in my opinion), is that *every* public
identifier in the OBJ file being imported *must* be declared as a
Pascal function or procedure identifier. This means that you will have
to be very careful to make *every* function that is local to the C
source a LOCAL (static) function. Kim Kokonnen has come up with another
solution to this problem -- see PATCHTPC for a program to patch TPC.EXE
to cure this nasty. (I've tried it and it seems to work ok).
---------------------------------------